home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
jnos
/
jnos_src
/
lxasy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-17
|
12KB
|
542 lines
/*
* File stolen from WAMPES 921229, modified for compatibility with JNOS and my
* tastes, and left to sink or swim. Blub! ++bsa
*
* The actual structure is much closer to that of JNOS than to WAMPES. The
* reason is that WAMPES uses these weirdball I/O hooks... We will use the
* "classic" interface, modified by the use of register_fd().
*
* This file should really be called posixasy.c, since it uses only POSIX entry
* points (as far as I can tell).
*/
#include <sys/types.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/time.h>
#include <errno.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "asy.h"
#include "timer.h"
#include "lxasy.h"
#include "hardware.h"
#include "devparam.h"
static int find_speed __ARGS((long speed));
static void pasy __ARGS((struct asy *asyp));
static void asy_tx __ARGS((int, void *, void *));
static void asy_input __ARGS((int, void *, void *));
struct asy Asy[ASY_MAX];
/*---------------------------------------------------------------------------*/
static struct {
long speed;
speed_t flags;
} speed_table[] = {
#ifdef B50
50, B50,
#endif
#ifdef B75
75, B75,
#endif
#ifdef B110
110, B110,
#endif
#ifdef B134
134, B134,
#endif
#ifdef B150
150, B150,
#endif
#ifdef B200
200, B200,
#endif
#ifdef B300
300, B300,
#endif
#ifdef B600
600, B600,
#endif
#ifdef B900
900, B900,
#endif
#ifdef B1200
1200, B1200,
#endif
#ifdef B1800
1800, B1800,
#endif
#ifdef B2400
2400, B2400,
#endif
#ifdef B3600
3600, B3600,
#endif
#ifdef B4800
4800, B4800,
#endif
#ifdef B7200
7200, B7200,
#endif
#ifdef B9600
9600, B9600,
#endif
#ifdef B19200
19200, B19200,
#endif
#ifdef B38400
38400, B38400,
#endif
#ifdef B57600
57600, B57600,
#endif
#ifdef B115200
115200, B115200,
#endif
#ifdef B230400
230400, B230400,
#endif
#ifdef B460800
460800, B460800,
#endif
-1, 0
};
/*---------------------------------------------------------------------------*/
static int
find_speed(speed)
long speed;
{
int i;
i = 0;
while (speed_table[i].speed < speed && speed_table[i+1].speed > 0)
i++;
return i;
}
/*---------------------------------------------------------------------------*/
/* Initialize asynch port "dev" */
int
asy_init(dev,ifp,arg1,arg2,bufsize,trigchar,monitor,speed,force,triglevel)
int dev;
struct iface *ifp;
char *arg1,*arg2; /* Attach args for address and vector */
int16 bufsize;
int trigchar;
char monitor;
long speed;
int force;
int triglevel;
{
register struct asy *ap;
char filename[80];
char *ifn;
int sp, fd;
struct termios termios;
ap = &Asy[dev];
/* UUCP locking with ASCII pid */
strcpy(ap->uulock, "/usr/spool/uucp/LCK..");
strcat(ap->uulock, arg1);
for (;;)
{
if ((fd = open(ap->uulock, O_WRONLY|O_CREAT|O_EXCL, 0644)) != -1 ||
errno != EEXIST)
break;
/* read pid, unlink and retry if proc no longer exists */
if ((fd = open(ap->uulock, O_RDONLY)) == -1)
continue; /* timing is everything */
filename[read(fd, filename, 10)] = '\0';
close(fd);
sscanf(filename, "%d", &fd);
if (kill(fd, 0) == -1 && errno == ESRCH)
{
tprintf("Removing stale lockfile for %s\n", arg1);
unlink(ap->uulock);
continue;
}
tprintf("/dev/%s is locked\n", arg1);
ap->uulock[0] = '\0'; /* so it won't clobber existing lock */
goto Fail;
}
if (fd == -1)
{
tprintf("Can't lock /dev/%s: %s\n", arg1, strerror(errno));
ap->uulock[0] = '\0';
goto Fail;
}
chmod(ap->uulock, 0644); /* beware of overly restrictive umask */
sprintf(filename, "%10d\n", getpid());
write(fd, filename, 11);
close(fd);
strcpy(filename, "/dev/");
strcat(filename, arg1);
if ((fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
{
tprintf("Can't open port: %s\n", strerror(errno));
goto Fail;
}
ap->iface = ifp;
sp = find_speed(speed);
ap->speed = speed_table[sp].speed;
memset((char *) &termios, 0, sizeof(termios));
termios.c_iflag = IGNBRK|IGNPAR;
termios.c_cflag = CS8|CREAD|CLOCAL|speed_table[sp].flags;
if (cfsetispeed(&termios, speed_table[sp].flags) == -1)
{
tprintf("Can't set speed: %s\n", strerror(errno));
goto Fail;
}
if (cfsetospeed(&termios, speed_table[sp].flags) == -1)
{
tprintf("Can't set speed: %s\n", strerror(errno));
goto Fail;
}
if (tcsetattr(fd, TCSANOW, &termios) == -1)
{
tprintf("Can't configure port: %s\n", strerror(errno));
goto Fail;
}
/* security: port won't work until re-opened */
if ((ap->fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
{
tprintf("Can't reopen port: %s\n", strerror(errno));
goto Fail;
}
close(fd);
ifp->txproc = newproc(ifn = if_name(ifp," tx"),
256, asy_tx, dev, ifp, NULL, 0);
free(ifn);
ap->rxproc = newproc(ifn = if_name(ifp, " asy rx"),
256, asy_input, dev, ifp, NULL, 0);
free(ifn);
register_io(ap->fd, &ap->fd);
return 0;
Fail:
rflush(); /* make sure the message gets out */
if (fd != -1)
close(fd);
/* Unlock port */
if (ap->uulock[0])
unlink(ap->uulock);
ap->uulock[0] = '\0';
ap->iface = NULLIF;
return -1;
}
/*---------------------------------------------------------------------------*/
int
asy_stop(ifp)
struct iface *ifp;
{
register struct asy *ap;
ap = &Asy[ifp->dev];
if(ap->iface == NULLIF)
return -1; /* Not allocated */
unregister_io(ap->fd);
if (ifp->txproc)
killproc(ifp->txproc);
ifp->txproc = 0;
if (ap->rxproc)
killproc(ap->rxproc);
ap->rxproc = 0;
ap->iface = NULLIF;
free_q(&ap->sndq);
close(ap->fd);
free_q(&ap->rcvq);
if (ap->uulock[0])
unlink(ap->uulock);
ap->uulock[0] = '\0';
return 0;
}
void
detach_all_asy()
{
register struct asy *ap;
for (ap = Asy; ap != Asy + ASY_MAX; ap++)
{
if(ap->iface == NULLIF)
break;
unregister_io(ap->fd);
if (ap->iface->txproc)
killproc(ap->iface->txproc);
ap->iface->txproc = 0;
if (ap->rxproc)
killproc(ap->rxproc);
ap->rxproc = 0;
ap->iface = NULLIF;
free_q(&ap->sndq);
free_q(&ap->rcvq);
close(ap->fd);
if (ap->uulock[0])
unlink(ap->uulock);
ap->uulock[0] = '\0';
}
}
/*---------------------------------------------------------------------------*/
/* Set asynch line speed */
int
asy_speed(dev,bps)
int dev;
long bps;
{
struct asy *asyp;
int sp;
struct termios termios;
if(bps <= 0 || dev >= ASY_MAX)
return -1;
asyp = &Asy[dev];
if(asyp->iface == NULLIF)
return -1;
if(bps == 0)
return -1;
sp = find_speed(bps);
if (tcgetattr(asyp->fd, &termios))
return -1;
if (cfsetispeed(&termios, speed_table[sp].flags))
return -1;
if (cfsetospeed(&termios, speed_table[sp].flags))
return -1;
termios.c_cflag &= ~CBAUD;
termios.c_cflag |= speed_table[sp].flags;
if (tcsetattr(asyp->fd, TCSANOW, &termios))
return -1;
asyp->speed = speed_table[sp].speed;
return 0;
}
/*---------------------------------------------------------------------------*/
/* Asynchronous line I/O control */
int32
asy_ioctl(ifp,cmd,set,val)
struct iface *ifp;
int cmd;
int set;
int32 val;
{
struct asy *ap = &Asy[ifp->dev];
switch(cmd){
case PARAM_SPEED:
if(set)
asy_speed(ifp->dev,val);
return ap->speed;
}
return -1;
}
/*---------------------------------------------------------------------------*/
#define RXCHUNK 64
static void
asy_input(dev, arg1, arg2)
int dev;
void *arg1, *arg2;
{
extern int errno;
struct asy *ap;
char *buf;
int i;
buf = mallocw(RXCHUNK);
ap = &Asy[dev];
for (;;)
{
do
{
if (pwait(&ap->fd) != 0)
{
free(buf);
return;
}
ap->rxints++;
}
while ((i = read(ap->fd, buf, RXCHUNK)) == 0 ||
(i == -1 && errno == EWOULDBLOCK));
/* gang-reading destroys JNOS response; no benefits seen */
#if 0
while (i > 0)
{
#endif
ap->rxchar += i;
enqueue(&ap->rcvq, qdata(buf, i));
#if 0
pwait(NULL); /* process it to avoid monopolizing cycles */
i = read(ap->fd, buf, RXCHUNK);
}
#endif
if (i == -1 && errno != EWOULDBLOCK)
{
free(buf);
return;
}
}
}
int
get_asy(dev)
int dev;
{
struct asy *ap;
ap = &Asy[dev];
if (ap->iface == NULLIF)
return -1;
while (!ap->rcvq)
{
if (pwait(&ap->rcvq) != 0)
return -1; /* may not be dead, e.g. alarm in dialer */
}
return PULLCHAR(&ap->rcvq);
}
/*---------------------------------------------------------------------------*/
int
doasystat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct asy *asyp;
struct iface *ifp;
int i;
if(argc < 2){
for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
if(asyp->iface != NULLIF)
pasy(asyp);
}
return 0;
}
for(i=1;i<argc;i++){
if((ifp = if_lookup(argv[i])) == NULLIF){
tprintf("Interface %s unknown\n",argv[i]);
continue;
}
for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
if(asyp->iface == ifp){
pasy(asyp);
break;
}
}
if(asyp == &Asy[ASY_MAX])
tprintf("Interface %s not asy\n",argv[i]);
}
return 0;
}
/*---------------------------------------------------------------------------*/
static void
pasy(asyp)
struct asy *asyp;
{
tprintf("%s: %lu bps\n", asyp->iface->name, asyp->speed);
tprintf(" RX: int %lu chars %lu\n",
asyp->rxints, asyp->rxchar);
tprintf(" TX: int %lu chars %lu\n",
asyp->txints, asyp->txchar);
}
/*---------------------------------------------------------------------------*/
/* Serial transmit process, common to all protocols */
static void
asy_tx(dev, p1, p2)
int dev;
void *p1, *p2;
{
register struct mbuf *bp;
struct asy *asyp;
asyp = &Asy[dev];
for (;;)
{
while (asyp->sndq == NULLBUF)
{
if (pwait(&asyp->sndq) != 0)
return;
asyp->txints++;
}
bp = dequeue(&asyp->sndq);
while (bp != NULLBUF)
{
write(asyp->fd, bp->data, bp->cnt);
asyp->txchar += bp->cnt;
bp = free_mbuf(bp);
}
pwait(NULL);
}
}
/*---------------------------------------------------------------------------*/
/* Send a message on the specified serial line */
int
asy_send(dev,bp)
int dev;
struct mbuf *bp;
{
struct asy *asyp;
if(dev < 0 || dev >= ASY_MAX){
free_p(bp);
return -1;
}
asyp = &Asy[dev];
if(asyp->iface == NULLIF)
free_p(bp);
else
enqueue(&asyp->sndq, bp);
return 0;
}
/* stub, CD not enabled at present */
int
carrier_detect(dev)
int dev;
{
return 1; /* assume always on, with CLOCAL it is! */
}